<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link rel="Stylesheet" type="text/css" href="doc.css" />
<title>Defining Custom Notifications</title>
</head>
<body>
<h1><a name="top">Defining Custom Notifications</a></h1>

<p>
Live validation determines the constraints to evaluate by the events that they declare as
triggers.  By default, support is provided for the standard event types defined by EMF:
<em class="CodeName">SET</em>, <em class="CodeName">ADD</em>, <em class="CodeName">REMOVE</em>,
etc.  However, sometimes these are too fine-grained, and accurately specifying the
triggering events for different features could be difficult, verbose, or even impossible.
</p>

<blockquote>
	<img src="images/notificationGenerator.png" alt="Notification Generator API"/><br/>
	<font size="-2">[<a href="images/notificationGenerator.svg">as SVG</a>]</font>
</blockquote>

<p>
Enter the <em class="UILabel">notification generator</em>.  This facility allows clients to
define custom event types that are more abstract.  For example, a constraint might be
triggered on additions or removals in any containment feature.  So, an application can
register a custom "ContainmentChange" event type on the
<a href="../extension-points/org_eclipse_emf_validation_eventTypes.html"><em class="CodeName">org.eclipse.emf.validation.eventTypes</em></a>
extension point.
</p>
<pre class="Code">
   &lt;extension
         point="org.eclipse.emf.validation.eventTypes"&gt;
      
      &lt;eventType
            <b>name</b>="ContainmentChange"
            <b>featureSpecific</b>="false"
            <b>notificationGenerator</b>="org.eclipse.example.ContainmentNotificationGenerator"&gt;
      &lt;/eventType&gt;
  &lt;/extension&gt;
</pre>
<p>
The <em class="CodeName">name</em> attribute specifies the non-localizable name that clients
will use in their live constraint declarations as a trigger.  If the event type is
feature-specific, then clients can also specify features to match along with the event type.
If the event type is not feature-specific, then it is considered to apply to the notifier
element as a whole.
</p>

<h2>The Notification Generator</h2>

<p>
The other key component of the event type declaration is the <em class="CodeName">notificationGenerator</em>.
This indicates a class implementing the
<a href="../javadoc/org/eclipse/emf/validation/service/INotificationGenerator.html"><em class="CodeName">INotificationGenerator</em></a>
that will be called upon during live validation to analyze the list of raw
<em class="CodeName">Notification</em>s and compute the custom notifications, if any.
Custom events created in this way are not fed recursively through the generation
process; only the basic notifications from the EMF content are processed in this way.
</p><p>
Custom event types are created implicitly by accessing their static instances in the
<a href="../javadoc/org/eclipse/emf/validation/EMFEventType.html"><em class="CodeName">EMFEventType</em></a>.
The framework automatically assigns them unique event type IDs that are different from
those pre-defined by EMF.
</p>
<pre class="Code">
    public Collection <b>generateNotifications</b>(Collection notifications) {
        Collection result = new ArrayList();
        
        for (Iterator iter = <b>notifications</b>.iterator(); iter.hasNext(); ) {
            Notification notification = (Notification) iter.next();
            Object feature = notification.getFeature();
            
            if ((feature instanceof EReference) &amp;&amp; ((EReference) feature).isContainment()) {
                Collection children = Collections.EMPTY_SET;
                
                switch (notification.getEventType()) {
                case Notification.ADD:
                    child1 = Collections.singleton(notification.getNewValue());
                    break;
                case Notification.REMOVE:
                    child1 = Collections.singleton(notification.getOldValue());
                    break;
                case Notification.SET:
                case Notification.UNSET:
                    children = new ArrayList(2);
                    children.add(notification.getNewValue());
                    children.add(notification.getOldValue());
                    break;
                case Notification.ADD_MANY:
                    children = (Collection) notification.getNewValue();
                    break;
                case Notification.ADD_REMOVE:
                    children = (Collection) notification.getOldValue();
                    break;
                }
                
                // create a ContainmentChange event from the child's perspective.
                // The EMFEventType class guarantees unique event type codes
                for (Iterator iter = children.iterator(); iter.hasNext();) {
                    result.add(new ENotificationImpl(
                        (InternalEObject) iter.next(),
                        EMFEventType.<b>getInstance</b>("ContainmentChange").<b>toNotificationType</b>(),
                        Notification.<b>NO_FEATURE_ID</b>, // non-feature-specific example
                        null, null));
                }
            }
        }
        
        return result;
    }
</pre>

<hr/>
<p>
<a href="https://www.eclipse.org/legal/epl-2.0/">Copyright (c) 2000, 2007 IBM Corporation and others.</a>
</p>
</body>
</html>
